package com.settlement.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.settlement.system.common.model.Option;
import com.settlement.system.mapper.SysLossMapper;
import com.settlement.system.model.entity.SysDict;
import com.settlement.system.model.entity.SysDictType;
import com.settlement.system.model.entity.SysLoss;
import com.settlement.system.model.entity.SysRole;
import com.settlement.system.model.form.LossForm;
import com.settlement.system.model.query.LossPageQuery;
import com.settlement.system.model.vo.LossResultVo;
import com.settlement.system.model.vo.SysLossImportVo;
import com.settlement.system.service.SysDictService;
import com.settlement.system.service.SysDictTypeService;
import com.settlement.system.service.SysLossService;
import com.settlement.system.service.SysRoleService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author huangrensen
 * @since 2023-08-24
 */
@Service
@RequiredArgsConstructor
public class SysLossServiceImpl extends ServiceImpl<SysLossMapper, SysLoss> implements SysLossService {

    private final SysRoleService sysRoleService;

    private final SysDictService sysDictService;

    private final SysDictTypeService sysDictTypeService;

    @Override
    public Page<SysLoss> getPage(LossPageQuery queryParams) {
        // 查询参数
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        String keywords = queryParams.getKeywords();
        // 查询数据
        Page<SysLoss> lossPage = this.page(new Page<>(pageNum, pageSize), new LambdaQueryWrapper<SysLoss>()
                .like(StrUtil.isNotBlank(keywords), SysLoss::getDetailName, keywords)
                .orderByDesc(SysLoss::getUpdateTime));
        List<SysLoss> lossList = lossPage.getRecords();
        List<Long> roleIds = lossList.stream().map(SysLoss::getRoleId).toList();
        if (roleIds.size() > 0) {
            List<SysRole> roles = sysRoleService.listByIds(roleIds);
            for (SysLoss loss : lossList) {
                loss.setRoleName(roles.stream().filter(dept -> Objects.equals(dept.getId(), loss.getRoleId())).findFirst().map(SysRole::getName).orElse(null));
            }
        }
        return lossPage;
    }

    @Override
    public SysLoss getLossFormData(Long lossId) {
        return this.baseMapper.selectById(lossId);
    }

    @Override
    public boolean saveLoss(LossForm lossForm) {
        SysLoss sysLoss = new SysLoss();
        BeanUtil.copyProperties(lossForm, sysLoss);
        if (sysLoss.getId() == null) {
            long count = this.count(new LambdaQueryWrapper<SysLoss>().eq(SysLoss::getDetailName, lossForm.getDetailName()));
            Assert.isTrue(count == 0, "损失原因细则名称已存在");
        } else {
            long count = this.count(new LambdaQueryWrapper<SysLoss>().eq(SysLoss::getDetailName, lossForm.getDetailName()).ne(SysLoss::getId, lossForm.getId()));
            Assert.isTrue(count == 0, "损失原因细则名称已存在");
        }
        return saveOrUpdate(sysLoss);
    }

    @Override
    public boolean deleteLosses(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "删除的损失原因数据为空");
        // 逻辑删除
        List<Long> ids = Arrays.stream(idsStr.split(",")).map(Long::parseLong).collect(Collectors.toList());
        return this.removeByIds(ids);
    }

    @Override
    public void importBatch(List<SysLossImportVo> vos) {
        // 检查数据完整性
        Assert.isTrue(vos.stream().noneMatch(vo -> StringUtils.isBlank(vo.getLossCode()) || StringUtils.isBlank(vo.getLossName())), "损失原因编码和损失原因一列不能为空");
        // 查询所有角色
        List<SysRole> roles = sysRoleService.list();
        for (SysLossImportVo vo : vos) {
            Assert.isTrue(roles.stream().anyMatch(role -> role.getName().equals(vo.getRoleName())), "系统不存在角色【%s】".formatted(vo.getRoleName()));
        }
        // 查找字典类型是否存在损失编码的配置
        List<SysDictType> lossList = sysDictTypeService.list(new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getCode, "loss"));
        if (lossList.size() == 0) {
            // 新建
            SysDictType sysDictType = new SysDictType();
            sysDictType.setCode("loss");
            sysDictType.setName("损失原因编码");
            sysDictType.setStatus(1);
            sysDictTypeService.save(sysDictType);
        }
        // 查出历史记录
        List<Option> options = sysDictService.listDictOptions("loss");
        List<SysDict> createSysDicts = new ArrayList<>();
        int index = 1;
        for (SysLossImportVo vo : vos) {
            if (options.stream().noneMatch(option -> option.getValue().equals(vo.getLossCode()) && option.getLabel().equals(vo.getLossName()))) {
                SysDict createObj = new SysDict();
                createObj.setTypeCode("loss");
                createObj.setValue(vo.getLossCode());
                createObj.setName(vo.getLossName());
                createObj.setSort(index);
                createObj.setRemark(vo.getLossExplain());
                createObj.setStatus(1);
                index++;
                if (createSysDicts.stream().noneMatch(create -> createObj.getValue().equals(create.getValue()))) {
                    createSysDicts.add(createObj);
                }
            }
        }
        // 创建新的记录
        if (createSysDicts.size() > 0) {
            for (SysDict createSysDict : createSysDicts) {
                sysDictService.save(createSysDict);
            }
        }
        // 按照损失编码分组
        Map<String, List<SysLossImportVo>> collect = vos.stream().collect(Collectors.groupingBy(SysLossImportVo::getLossCode));
        // 删除旧的记录，插入新的数据
        List<SysLoss> createObjs = new ArrayList<>();
        collect.forEach((lossCode, list) -> {
            // 删除
            List<SysLoss> sysLosses = this.list(new LambdaQueryWrapper<SysLoss>().eq(SysLoss::getLossCode, lossCode));
            if (sysLosses.size() > 0) {
                for (SysLoss sysLoss : sysLosses) {
                    this.baseMapper.deleteById(sysLoss);
                }
            }
            for (SysLossImportVo vo : list) {
                // 新增
                SysLoss sysLoss = new SysLoss();
                BeanUtil.copyProperties(vo, sysLoss);
                sysLoss.setDetailCode(this.nextCode(sysLoss.getLossCode()).getDetailCode());
                roles.stream().filter(role -> role.getName().equals(vo.getRoleName())).findFirst().ifPresent(role -> sysLoss.setRoleId(role.getId()));
                createObjs.add(sysLoss);
                this.save(sysLoss);
            }
        });
    }

    @Override
    public List<SysLossImportVo> listExportLosses() {
        List<SysLoss> list = this.list();
        // 查询所有角色
        List<SysRole> roles = sysRoleService.list();
        List<SysLossImportVo> sysLossImportVos = new ArrayList<>();
        for (SysLoss sysLoss : list) {
            SysLossImportVo importVo = new SysLossImportVo();
            BeanUtil.copyProperties(sysLoss, importVo);
            importVo.setRoleName(roles.stream().filter(role -> role.getId().equals(sysLoss.getRoleId())).map(SysRole::getName).findFirst().orElse(null));
            sysLossImportVos.add(importVo);
        }
        return sysLossImportVos;
    }

    @Override
    public LossResultVo nextCode(String code) {
        LossResultVo vo = new LossResultVo();
        long count = this.count(new LambdaQueryWrapper<SysLoss>().eq(SysLoss::getLossCode, code));
        vo.setDetailCode("%s_%d".formatted(code, count + 1));
        List<SysDict> dictList = sysDictService.listByTypeCodeAndValue("loss", code);
        vo.setLossExplain(dictList.get(0).getRemark());
        return vo;
    }

    @Override
    public List<LossResultVo> listAll() {
        List<SysLoss> list = this.list();
        // 查询所有角色
        List<SysRole> roles = sysRoleService.list();
        List<LossResultVo> vos = new ArrayList<>();
        for (SysLoss sysLoss : list) {
            LossResultVo vo = new LossResultVo();
            vo.setDetailName(sysLoss.getDetailName());
            vo.setLossCode(sysLoss.getLossCode());
            vo.setDetailCode(sysLoss.getDetailCode());
            vo.setOrderStatusName(sysLoss.getOrderStatusName());
            vo.setRoleId(sysLoss.getRoleId());
            vo.setRoleName(roles.stream().filter(role -> role.getId().equals(sysLoss.getRoleId())).map(SysRole::getName).findFirst().orElse(null));
            vo.setRoleCode(roles.stream().filter(role -> role.getId().equals(sysLoss.getRoleId())).map(SysRole::getCode).findFirst().orElse(null));
            vos.add(vo);
        }
        return vos;
    }
}
